<?php

namespace utils;

use app\model\Rules;
use app\model\Users;
use Hidehalo\Nanoid\Client;
use think\facade\Cache;

class Auth
{
    /**
     * 生成一个唯一token
     * @param mixed $play_load 载荷
     * @param int $expiration_time 过期时间|3600
     * */
    public static function createToken($play_load, $expiration_time = 3600)
    {
        $client = new Client();
        $token = $client->generateId(21);
        Cache::set($token, $play_load, $expiration_time);
        return $token;
    }

    /**
     * @param $token
     * @return false|mixed
     */
    public static function verifyToken($token): mixed
    {
        $result = Cache::get($token);
        if ($result === null) return false;
        return $result;
    }

    /**
     * @param $token string
     * @return void
     */
    public static function cancelToken(string $token)
    {
        Cache::delete($token);
    }

    /**
     * @param $rules array|string 需要校验的规则
     * @param $uid int 用户ID
     * @param $type string 校验关系类型，默认 or
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function check(array|string $rules, int $uid, string $type = 'or'): bool
    {
        $user = Users::find($uid);
        if (empty($user)) return false;
        if ($user->status !== 1) return false;
        $user_rule_list = explode(',', $user->group->rules);
        $user_rule_name_list = $this->getRulesName($user_rule_list);
        $rule_list = explode(',', $rules);
        // 如果拥有管理员权限则直接返回真
        if (in_array('admin', $user_rule_name_list)) return true;

        $_check_status = false;

        foreach ($rule_list as $key => $rule) {
            if (!in_array($rule, $user_rule_list) &&
                !in_array($rule, $user_rule_name_list) &&
                $type === 'and') {
                return false;
            }
            if (in_array($rule, $user_rule_list) || in_array($rule, $user_rule_name_list)) {
                if ($type === 'or') {
                    return true;
                } elseif ($type === 'and') {
                    // 当类型为 and 时，有三种情况 第一次验证通过 非第一次验证失败 非第一次验证通过
                    if ($key !== 0) {
                        if ($_check_status === false) return false;
                    }
                    $_check_status = true;
                }
            }
        }
        return $_check_status;
    }

    public function getRulesName($rule_list): array
    {
        $rule_name_list = [];
        foreach ($rule_list as $rule) {
            $rule_obj = Rules::find($rule);
            if (!empty($rule_obj)) $rule_name_list[] = $rule_obj->rule;
        }
        return $rule_name_list;
    }
}